package com.marketlive.app.b2c;

/**
 * (C) Copyright MarketLive. 2006. All rights reserved.
 * MarketLive is a trademark of MarketLive, Inc.
 * Warning: This computer program is protected by copyright law and international treaties.
 * Unauthorized reproduction or distribution of this program, or any portion of it, may result
 * in severe civil and criminal penalties, and will be prosecuted to the maximum extent
 * possible under the law.
 */

import com.marketlive.app.b2c.common.constants.RequestParams;
import com.marketlive.app.b2c.nav.ILinkGenerator;

import org.marketlive.entity.IEntity;


import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.PageContext;

/**
 * This class provides the JSTL-EL interface to the NavState functions which build entity reference URLs.
 * Added functions to support generation of RSS Feed URLs for category entities.
 *
 * @author bcarp
 * @author Anup
 *
 */
public final class NavFunctions {

    /** path cache for entities and paths. */
    private static Hashtable pathCache = new Hashtable();

    /**
     * Pattern to match special characters which must be escaped
     * in a javascript string.  The two characters are single quote '
     * and backslash \  In order to match against backslash, the pattern
     * should contain \\, but in order to do that in java, we must
     * escape each \ resulting in \\\\ to create a pattern to match \\.
     * Note: Pattern objects are immutable and are safe for use by
     * multiple concurrent threads.
     */
    private static final Pattern ESCAPE_SPECIAL_CHARS_PATTERN = Pattern.compile("(['\\\\])");

    /**
     * Hidden default constructor.
     */
    private NavFunctions() {
        // Empty constructor.
    }

    /**
     * Creates entity reference using the NavState's current product or category if either of those is available.
     *
     * @param context page context
     * @return String entity url
     */
    public static String defaultEntityRef(PageContext context) {

        return getLinkGenerator(context).defaultEntityRef(getNavState(context));
    }

    /**
     * Creates entity references using specified entity.
     *
     * @param entity entity object
     * @param context page context
     * @return String url
     */
    public static String entityRef(IEntity entity, PageContext context) {
        return entityRefAddPath(entity, null, context);
    }

    /**
     * Creates entity references using specified entity.
     *
     * @param entity entity object
     * @param context page context
     * @return String url
     */
    public static String entityRSSRef(IEntity entity, PageContext context) {
        return entityRefAddPath(entity, null, context, true);
    }


    /**
     * Creates entity references using specified entity and optional additional URL path.
     *
     * @param entity entity object
     * @param additionalPath url path suffix
     * @param context page context
     * @return String url
     */
    public static String entityRefAddPath(IEntity entity, String additionalPath, PageContext context) {
        return entityRefAddPath(entity, additionalPath, context, false);
    }

    /**
     * Creates entity references using specified entity and optional additional URL path.
     *
     * @param entity entity object
     * @param additionalPath url path suffix
     * @param context page context
     * @param isRSSRef boolean to specify if requested Ref is for RSS category.
     * @return String url
     */
    public static String entityRefAddPath(IEntity entity, String additionalPath, PageContext context, boolean isRSSRef) {
        if (entity == null) {
            return "";
        }

        return getLinkGenerator(context).entityRefAddPath(entity, additionalPath, getNavState(context), isRSSRef);
    }

    /**
     * Creates URL path with NavState encoded parameters.
     *
     * @param path path to create url
     * @param context page context
     * @return String url
     */
    public static String pathRef(String path, PageContext context) {
        if (path == null) {
            return "";
        }

        return getLinkGenerator(context).pathRef(path, getNavState(context));
    }

    /**
     * Removes URL query parameter from URL.
     *
     * @param url url to remove parameter from
     * @param parameter query parameter to remove
     * @return String url
     */
    public static String removeQueryParameter(String url, String parameter) {

        // If either of parameters is null, just return url unchanged.
        //
        if (url == null || parameter == null) {
            return url;
        }

        // Remove parameter at beginning of query parameters. urlPath?parameter=value
        //
        String removed = url.replaceFirst("\\?" + parameter + "=[a-zA-Z\\d]+&*", "?");

        // Remove &parameter=value parameters.
        //
        return removed.replaceAll("&" + parameter + "=[a-zA-Z\\d]+", "");
    }
    
    /**
     * Removes all query parameters from the given URL.
     * 
     * @param url url to remove parameters from.
     * @return String urlWithNoParameter
     */
    public static String removeAllQueryParameters(String url) {
    	String urlWithNoParameter = "";
    	
    	// If given url is null or empty, just return url unchanged.
    	if (url == null || url.equalsIgnoreCase("")) { 
            return url;
        }
    	
    	int index = url.indexOf("?");    	
    	
    	// Substring "?" must be present.
    	if (index != -1) {
    		urlWithNoParameter = url.substring(0, index);
    	}
    	
    	return urlWithNoParameter;     	
    }

    /**
     * Escapes any special characters found in the input string.  This
     * is needed in order to pass string parameters to Javascript functions
     * which contain single quotes and backslashes.
     *
     * Escaped ' becomes \' and \ becomes \\
     *
     * @param value string to modify
     * @return String string with special characters escaped
     */
    public static String escapeSpecialChars(String value) {

        // If value is null, just return value unchanged.
        //
        if (value == null) {
            return value;
        }

        // Replace special characters (' and \ for 5.3) with \' and \\.
        // In order to do that, the replace should contain \\ (backslash
        // character). To do that in java must escape \ with \, resulting
        // in \\\\ to get \\ in the replacement pattern.  The $0 is a back
        // reference to the special character that matched.
        //
        return ESCAPE_SPECIAL_CHARS_PATTERN.matcher(value).replaceAll("\\\\$0");
    }

    /**
     * Returns the Link Generator bean from the application context.
     *
     * @param context page context
     * @return ILinkGenerator link generator object
     */
    private static ILinkGenerator getLinkGenerator(PageContext context) {

        return WebUtil.getLinkGenerator((HttpServletRequest) context.getRequest());
    }

    /**
     * Returns the NavState object found in the servlet request scope.
     *
     * @param context page context
     * @return NavState navigation state object
     */
    private static NavState getNavState(PageContext context) {

        // The NavState is a request context attribute.
        return (NavState) context.getAttribute(RequestParams.NAVSTATE, PageContext.REQUEST_SCOPE);
    }

    /** Prepends the code for the user's active locale to the given URI, only if the active locale
     *  is different from the site's default locale.
     *
     * @param path
     */
    public static String urlWrapper(String path,PageContext context) {
        if (path == null) {
            return "";
        }
        Locale bLocale = new Locale("en", "US");
        return getLinkGenerator(context).wrapURI(path, bLocale);
    }
   
}
